package org.ehl.listener;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.ehl.annotation.Controller;
import org.ehl.annotation.RequestMapping;
import org.ehl.core.entity.AnnotationBean;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

public class InitListener implements ServletContextListener {
	private static Map<String, AnnotationBean> handlerMapping = new HashMap<String, AnnotationBean>();

	@Override
	public void contextDestroyed(ServletContextEvent arg0) {

	}

	@Override
	public void contextInitialized(ServletContextEvent event) {
		System.out.println("******************************************");
		System.out.println("contextListener init .....");
		String root = event.getServletContext().getRealPath("");
		String contextConfigLocation = event.getServletContext().getInitParameter("contextConfigLocation");
		String configPath = root;
		if (contextConfigLocation == null) {
			configPath = root + "/WEB-INF/application-mvc.xml";
		} else if (contextConfigLocation.indexOf("classpath:") != -1) {
			configPath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + contextConfigLocation.substring(contextConfigLocation.indexOf(":") + 1);
		}
		File configFile = new File(configPath);
		if (!configFile.exists()) {
			throw new RuntimeException("缺少" + configPath + "配置文件");
		}
		String location = getScanPath(configFile).trim();
		String scanPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();

		if (location.endsWith("*")) {
			String tem = scanPath + location.substring(0, location.length() - 1).replace(".", "/");
			File scanFile = new File(tem);
			lookupFile(scanFile, true);
		} else {
			String tem = scanPath + location.replace(".", "/");
			File scanFile = new File(tem);
			lookupFile(scanFile, false);
		}
		event.getServletContext().setAttribute("handlerMapping", handlerMapping);
		System.out.println(handlerMapping);

	}

	/**
	 * 获取扫描目录
	 * 
	 * @param configFile
	 * @return
	 */
	private static String getScanPath(File configFile) {
		SAXBuilder builder = new SAXBuilder();
		try {
			Document doc = builder.build(configFile);
			Element root = doc.getRootElement();
			String location = root.getChild("scan").getAttribute("location").getValue();
			return location;
		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 循环便利文件
	 * 
	 * @param file
	 * @param findChildPath
	 *            是否穷举所有目录
	 */
	public static void lookupFile(File file, boolean findChildPath) {

		if (findChildPath) {
			// 完全便利
			if (file.isDirectory()) {
				File[] childrens = file.listFiles();
				if (childrens != null) {
					for (File child : childrens) {
						if (child.isDirectory()) {
							lookupFile(child, findChildPath);
						} else {
							// 解析文件
							addElement(child);
						}
					}
				}
			}

		} else {
			// 只便利一层
			if (file.isDirectory()) {
				File[] childrens = file.listFiles();
				if (childrens != null) {
					for (File child : childrens) {
						if (!child.isDirectory()) {

							// 解析文件
							addElement(child);
						}
					}
				}
			}
		}

	}

	/**
	 * 解析文件
	 * 
	 * @param file
	 */
	private static void addElement(File file) {
		String classFileName = file.getName();
		String absolutePath = file.getAbsolutePath();
		String packagepath = absolutePath.substring(absolutePath.indexOf("WEB-INF\\classes\\") + 16);
		packagepath = packagepath.replace("\\", ".");
		packagepath = packagepath.substring(0, packagepath.lastIndexOf("."));
		System.out.println("正在解析：" + packagepath + ".java 文件");
		try {
			Class<?> clazz = Class.forName(packagepath);

			Controller controller = clazz.getAnnotation(Controller.class);
			if (controller != null) {
				// 处理class
				AnnotationBean annotationBean = new AnnotationBean();
				String path = controller.value();
				System.out.println("注解的value = " + path);
				if (!path.startsWith("/")) {
					path = "/" + path;
				}
				annotationBean.setActionClass(packagepath);
				annotationBean.setPath(path);
				annotationBean.setName(clazz.getName() );
				// 处理method
				Method[] methods = clazz.getDeclaredMethods();
				if (methods == null) {
					System.out.println(packagepath + "类中没有被RequestMapping注解的方法");
				} else {
					for (Method method : methods) {
						System.out.println("解析到方法：" + method.getName());

						RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
						if (requestMapping != null && Modifier.isPublic(method.getModifiers())) {
							// 即被注解也被public 修饰
							System.out.println(method.getName() + "方法被注解和 被 public 修饰");

							String methodValue = requestMapping.value();
							annotationBean.getMethodMapping().put(methodValue, method.getName());
							handlerMapping.put(path, annotationBean);
						} else {
							System.out.println(method.getName() + "方法未被注解");
						}
					}
				}

			} else {
				System.out.println(packagepath + "未被注解");
			}
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
